package cn.am.service.impl;

import cn.kust.microtourismcommon.constant.PathConstants;
import cn.kust.microtourismcommon.pojo.dto.ResponseResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import cn.am.pojo.InterestPoint;
import cn.am.service.PathService;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;

/**
 * @Author : ArturiaMu KMUST-Stu
 * @Date : 2022/7/28 10:49
 * @Params : @param null
 * @Exception :
 * @Return :
 * @Description ：
 */
@Service
public class PathServiceImpl implements PathService {

    @Resource
    private RestTemplate restTemplate;

    private static final double EARTH_RADIUS = 6371000;//赤道半径(单位m)

    /**
     * 转化为弧度(rad)
     */
    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }

    /**
     * @param lon1 第一点的经度
     * @param lat1 第一点的纬度
     * @param lon2 第二点的经度
     * @param lat2 第二点的纬度
     * @return 返回的距离，单位m
     */
    public static double getDistance(double lon1, double lat1, double lon2, double lat2) {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lon1) - rad(lon2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000) / 10000;
        return s;
    }

    public static double getDisFromIP(InterestPoint origin, InterestPoint target) {
        String[] oriAdd = origin.getAdd().split(",");
        double oriLon = Double.parseDouble(oriAdd[0]);
        double oriLat = Double.parseDouble(oriAdd[1]);

        String[] tarAdd = target.getAdd().split(",");
        double tarLon = Double.parseDouble(tarAdd[0]);
        double tarLat = Double.parseDouble(tarAdd[1]);

        return getDistance(oriLon, oriLat, tarLon, tarLat);
    }

    @Override
    public ResponseResult<Map<Integer, List<InterestPoint>>> pathPlan(List<InterestPoint> interestPoints) {
        if (interestPoints == null || interestPoints.size() == 0) {
            return null;
        }
        if (interestPoints.size() == 1) {
            Map<Integer, List<InterestPoint>> plan = new HashMap<>();
            plan.put(1, interestPoints);
            return ResponseResult.success(plan);
        }
        Boolean[] flags = new Boolean[interestPoints.size()];
        Arrays.fill(flags, false);
        List<InterestPoint> sortedInterestPoints = new ArrayList<>();
        sortedInterestPoints.add(interestPoints.get(0));
        flags[0] = true;

        while (sortedInterestPoints.size() != interestPoints.size()) {
            InterestPoint origin = sortedInterestPoints.get(sortedInterestPoints.size() - 1);
            double minDis = Double.MAX_VALUE;
            int target = -1;
            for (int i = 0; i < interestPoints.size(); i++) {
                if (flags[i]) {
                    continue;
                }
                InterestPoint targetPoint = interestPoints.get(i);
                double dis = getDisFromIP(origin, targetPoint);
                if (dis < minDis) {
                    minDis = dis;
                    target = i;
                }
            }
            sortedInterestPoints.add(interestPoints.get(target));
            flags[target] = true;
        }

        System.out.println(sortedInterestPoints);

        Map<Integer, List<InterestPoint>> plan = new HashMap<>();

        int day = 1;
        double time_left = PathConstants.PLAY_TIME * 60;  // 480分钟
        double speed = PathConstants.CITY_AVG_SPEED;

        List<InterestPoint> stack = new ArrayList<>();

        for (int i = 0; i < sortedInterestPoints.size(); i++) {
            if (stack.size() == 0) {
                stack.add(sortedInterestPoints.get(i));
                time_left -= sortedInterestPoints.get(i).getTime();
                if (i == sortedInterestPoints.size() - 1) {
                    List<InterestPoint> day_list = new ArrayList<>(stack);
                    plan.put(day, day_list);
                }
                continue;
            }
            double distance = getDisFromIP(stack.get(stack.size() - 1), sortedInterestPoints.get(i)) / 1000;  // 千米
            double dri_time = distance / speed * 60;  // 分钟
            double total_time = dri_time + sortedInterestPoints.get(i).getTime();  // 分钟

            String url = PathConstants.BASE_URL + "&origin=" + stack.get(stack.size() - 1).getAdd() + "&destination=" + sortedInterestPoints.get(i).getAdd();
            String js = restTemplate.getForObject(url, String.class);
            JSONObject jsonObject = JSON.parseObject(js);
            double t = jsonObject.getJSONObject("route").getJSONArray("paths").getJSONObject(0).getDouble("duration");
            total_time = t / 60 + distance / speed * 60;

            if (time_left >= total_time) {
                stack.add(sortedInterestPoints.get(i));
                time_left -= total_time;
            } else {
                List<InterestPoint> day_list = new ArrayList<>(stack);
                plan.put(day, day_list);
                stack.clear();
                time_left = PathConstants.PLAY_TIME * 60;
                day++;
                i--;
            }
        }
        return ResponseResult.success(plan);
    }
}
